package com.gw.config;

import com.alibaba.fastjson.JSON;
import com.gw.filter.MyFilter;
import com.gw.service.UserService;
import com.gw.util.JwtUtil;
import com.gw.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Autowired
    private UserService userService;

    @Autowired
    private MyFilter filter;
    //指定账户和密码的来源
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.userDetailsService(userService).passwordEncoder(passwordEncoder());  
    }

    //设置security认证的规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
        //指定登录表单的规则
        http.formLogin()
                //这个路径必须和登录表单的提交路径一致。
                .loginProcessingUrl("/login")
                //设置自定义登录界面
//                .loginPage("/login1.html")
                //登录成功后转发的路径
//                .successForwardUrl("/main")
                //成功登陆后的业务代码
                .successHandler(successHandler())
                //认证失败后进入处理的业务代码
                .failureHandler(failureHandler())
                .permitAll();

        //没有权限时跳转的路径
        http.exceptionHandling().accessDeniedHandler(deniedHandler());
        
       //禁用跨站伪造请求,不使用csrf过滤器。
        http.csrf().disable();

        //允许跨域
        http.cors();

        //设置其他路径需要认证后才能访问
        http.authorizeRequests().anyRequest().authenticated();

    }

    private AccessDeniedHandler deniedHandler(){
        return (request, response, e) -> {
            response.setContentType("json/application;charset=utf-8");
            PrintWriter writer = response.getWriter();
            Result result=new Result(4003,"权限不足",null);
            String jsonString = JSON.toJSONString(result);

            writer.print(jsonString);

            writer.flush();
            writer.close();
        };
    }

    private AuthenticationFailureHandler failureHandler() {
        return (request, response, e) -> {
            response.setContentType("json/application;charset=utf-8");
            PrintWriter writer = response.getWriter();
            Result result=new Result(5000,"账户或密码错误",null);
            String jsonString = JSON.toJSONString(result);

            writer.print(jsonString);

            writer.flush();
            writer.close();

        };
    }

    private AuthenticationSuccessHandler successHandler() {
        return (request, response, authentication) -> {
            response.setContentType("json/application;charset=utf-8");
            //登录成功的业务代码.---servlet可以通过该对象输出json数据。
            PrintWriter writer = response.getWriter();

            //json数据
            //账户和该账户具有的权限放入到token令牌中
            User principal = (User) authentication.getPrincipal();
            //账户
            String username = principal.getUsername();
            Collection<GrantedAuthority> authorities = principal.getAuthorities();
            //权限
            List<String> collect = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());

            Map<String,Object> map=new HashMap<>();
            map.put("username",username);
            map.put("authorities",collect);

            String token= JwtUtil.createToken(map);

            Result result=new Result(2000,"登录成功",token);

            String jsonString = JSON.toJSONString(result);

            writer.print(jsonString);

            writer.flush();
            writer.close();


        };
    }
}